#include <iostream>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include "gradient.h"

using namespace std;

Colour Gradient::getColourSlow(double mu) {
	assert(this->size() > 1);
	Colour low, high, colour;
	double region = 1 / ((double)this->size() - 1);
	int whole = (int)(mu / region);
	double fraction = (mu - (whole * region)) * (1 / region);
	std::list<Colour>::iterator iter = begin();
	while (whole > 0) {
		++iter;
		--whole;
	}
	low = *iter;
	if (mu != 1) {
		++iter;
		high = *iter;
	} else {
		high = low;
	}
	colour.channel[CHANNEL_R] = (uint8_t)(((double)low.getR() * (1.0f - fraction)) + ((double)high.getR() * fraction));
	colour.channel[CHANNEL_G] = (uint8_t)(((double)low.getG() * (1.0f - fraction)) + ((double)high.getG() * fraction));
	colour.channel[CHANNEL_B] = (uint8_t)(((double)low.getB() * (1.0f - fraction)) + ((double)high.getB() * fraction));
	colour.channel[CHANNEL_A] = (uint8_t)(((double)low.getA() * (1.0f - fraction)) + ((double)high.getA() * fraction));
	return colour;
}

static Colour readColour(char *string);
static Gradient readLine(char *line);

void Gradient::generateColourTable() {
	if (colourTable) {
		delete [] colourTable;
	}
	colourTable = new Colour[COLOUR_TABLE_ENTRIES];
	if (colourTable == NULL) {
		std::cerr << "error allocating colour table memory\n";
		return;
	}
	for (int i = 0; i < COLOUR_TABLE_ENTRIES; i++) {
		colourTable[i] = getColourSlow(((double)i) / COLOUR_TABLE_ENTRIES);
	}
}

vector<Gradient> initGradients() {
	const char *delim = "\n";
	char *save;
	char *p;
	char gradientStr[] =	"(0,0,0) (255,0,0) (255,255,0) (0,255,0) (0,255,255) (0,0,255) (0,0,0)\n"
							"(0,0,0) (255,0,0) (255,255,0) (255,255,255)\n"
							"(0,0,0) (64,96,255) (255,255,255) (255,112,16) (0,0,0)\n"
							"(0,0,0) (255,0,255) (0,255,0) (0,0,0)\n"	
							"(0,0,0) (255,255,255)\n"
	;
	
	vector<Gradient> gradients;
	for (p = strtok_r(gradientStr, delim, &save); p; p = strtok_r(NULL, delim, &save)) {
		gradients.push_back(readLine(p));
	}
	if (gradients.size() < 1) {
		Gradient gradient;
		gradient.push_back(Colour(0, 0, 0));
		gradient.push_back(Colour(255, 255, 255));
		gradients.push_back(gradient);
	}
	return gradients;
}

static Gradient readLine(char *line) {
	Gradient gradient;

	const char *delim = " ;";
	char *save;
	char *p;

	for (p = strtok_r(line, delim, &save); p; p = strtok_r(NULL, delim, &save)) {
		gradient.push_back(readColour(p));
	}
	
	// stop a crash.. dummy monochrome gradient
	if (gradient.size() < 2) {
		gradient.push_back(Colour(0, 0, 0));
		gradient.push_back(Colour(255, 255, 255));
	}
	
	return gradient;
}

static Colour readColour(char *string) {
	int r = 0, g = 0, b = 0;
	sscanf(string, "(%d,%d,%d)", &r, &g, &b);
	return Colour(r, g, b);
	
}
